#include "fsm.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

fsm_t *FSM_INIT(int initSeq, fsm_seq_t *fs, int sizSeq){

    if(fs == NULL || sizSeq <= 0)
        return NULL;

    fsm_t *ret = (fsm_t *)malloc(sizeof(fsm_t));
    fsm_seq_t *bufSeq = (fsm_seq_t *)malloc(sizeof(fsm_seq_t) * sizSeq);
    memcpy(bufSeq, fs, sizeof(fsm_seq_t) * sizSeq);

    ret->pend = 0;
    ret->curSeq = initSeq;
    ret->sizSeq = sizSeq;
    ret->fs = bufSeq;
#ifdef FSM_MULTHD_ENABLE
    pthread_mutex_init(&(ret->mutex), NULL);
#endif
    return ret;
}

int FSM_GETSEQ(fsm_t *fsm){

    int ret = -1;

    if(fsm != NULL){
#ifdef FSM_MULTHD_ENABLE
        pthread_mutex_lock(&(fsm->mutex));
#endif
        ret = fsm->curSeq;
#ifdef FSM_MULTHD_ENABLE
        pthread_mutex_unlock(&(fsm->mutex));
#endif
    }

    return ret;
}

int FSM_PEND(fsm_t *fsm, int set){

    if(fsm != NULL){
#ifdef FSM_MULTHD_ENABLE
        pthread_mutex_lock(&(fsm->mutex));
#endif
        fsm->pend = set?1:0;
#ifdef FSM_MULTHD_ENABLE
        pthread_mutex_unlock(&(fsm->mutex));
#endif
        return 0;
    }

    return -1;
}

void FSM_DESTORY(fsm_t *fsm){

    if(fsm != NULL){
        if(fsm->fs != NULL){
            free(fsm->fs);
#ifdef FSM_MULTHD_ENABLE
            pthread_mutex_destroy(&(fsm->mutex));
#endif
        }
        free(fsm);
    }
}

int FSM_EVENT(fsm_t *fsm, int event){

    if(fsm == NULL)
        return -1;

    int ret = -1;
    fsm_handler_t _handler = NULL;
    int _argCurSeq, _argEvent, _argNextSeq;
#ifdef FSM_MULTHD_ENABLE
    pthread_mutex_lock(&(fsm->mutex));
#endif
    if(fsm != NULL && fsm->pend == 0){
        for(int x = 0; x < fsm->sizSeq; x++){
            if(fsm->fs[x].seq == fsm->curSeq){
                for(int y = 0; y < FSM_ENH_SIZE; y++){
                    if((fsm->fs[x]).enh[y].event == event){
                        _handler = (fsm->fs[x]).enh[y].handler;
                        _argCurSeq = fsm->curSeq;
                        _argEvent = event;
                        _argNextSeq = (fsm->fs[x]).enh[y].nextSeq;
                        // (fsm->fs[x]).enh[y].handler(fsm->curSeq, event, (fsm->fs[x]).enh[y].nextSeq);
                        // printf("seq: %d -> %d\n", fsm->curSeq, (fsm->fs[x]).enh[y].nextSeq);
                        fsm->curSeq = (fsm->fs[x]).enh[y].nextSeq;
                        ret = 0;
                        break;
                    }
                }
                break;
            }
        }
    }
#ifdef FSM_MULTHD_ENABLE
    pthread_mutex_unlock(&(fsm->mutex));
#endif
    if(_handler != NULL){
        _handler(_argCurSeq, _argEvent, _argNextSeq);
    }

    return ret;
}
